import { Component, OnInit, AfterViewInit, HostListener, ViewContainerRef, Renderer2, Type, Injector, ComponentRef, ComponentFactoryResolver, ViewChild, TemplateRef, EventEmitter } from '@angular/core';
import { FeaturePropertyOptionService, FeaturePropertySubjectService } from '../feature-property-ref.class';
import { Store } from '@ngrx/store';
import { State } from '../../../../store';
import * as fromLayersSelector from '../../../store/selectors/layer.selector';
import { NzModalService } from 'ng-zorro-antd';
import { PhotoViewerComponent } from '../components/photo-viewer/photo-viewer.component';

@Component({
  selector: 'ege-feature-property',
  templateUrl: './feature-property.component.html',
  styleUrls: ['./feature-property.component.scss']
})
export class FeaturePropertyComponent<T = any> implements OnInit, AfterViewInit {

  title: string;
  content: string | TemplateRef<{}> | Type<T>;
  componentParams: any;

  close$: EventEmitter<any> = new EventEmitter();

  private bottom: number = 0;
  private contentComponentRef: ComponentRef<T>;

  @ViewChild('bodyContainer', { read: ViewContainerRef }) bodyContainer: ViewContainerRef;

  constructor(
    private store: Store<State>,
    private viewContainerRef: ViewContainerRef,
    private renderer: Renderer2,
    private cfr: ComponentFactoryResolver,
    private options: FeaturePropertyOptionService,
    private modalService: NzModalService
  ) { 
    this.title = this.options.title;
    this.content = this.options.component;
    this.componentParams = this.options.componentParams;
    this.close$.subscribe(() => this.onClickClose());
  }

  ngOnInit() {
    this.setLayout();
    this.store.select(fromLayersSelector.getTableState).subscribe(visible => {
      switch(visible) {
        case 'visible': {
          this.bottom = 340;
          break;
        }
        case 'hidden': {
          this.bottom = 55;
          break;
        }
        default: {
          this.bottom = 0;
          break;
        }
      }
      this.setLayout();
    });
    if (this.isComponent(this.content)) {
      this.createDynamicComponent(this.content as Type<T>); // Create component along without View
    }
  }

  ngAfterViewInit(): void {
    this.setLayout();
    if (this.contentComponentRef) {
      this.bodyContainer.insert(this.contentComponentRef.hostView);
    }
  }

  @HostListener('window:resize', ['$event'])
  onWindowResize(event): void {
    this.setLayout();    
  }

  private setLayout(): void {
    const header: HTMLElement = this.viewContainerRef.element.nativeElement.querySelector('.properties-header');
    const main: HTMLElement = this.viewContainerRef.element.nativeElement.querySelector('.properties-main');
    const footer: HTMLElement = this.viewContainerRef.element.nativeElement.querySelector('.properties-footer');
    const maxHeight = window.innerHeight - 136 - header.offsetHeight - footer.offsetHeight - this.bottom - 16;
    this.renderer.setStyle(main, 'max-height', `${maxHeight}px`);
  }

  private isComponent(value: {}): boolean {
    return value instanceof Type;
  }

  private createDynamicComponent(component: Type<T>): void {
    const factory = this.cfr.resolveComponentFactory(component);
    const childInjector = Injector.create({
      providers: [{ provide: FeaturePropertySubjectService, useValue: {
        title: this.title,
        params: this.componentParams,
        close$: this.close$
      } }],
      parent   : this.viewContainerRef.parentInjector
    });
    this.contentComponentRef = factory.create(childInjector);
    // Do the first change detection immediately (or we do detection at ngAfterViewInit, multi-changes error will be thrown)
    this.contentComponentRef.changeDetectorRef.detectChanges();
  }

  onClickClose(): void {
    this.options.close$ && this.options.close$.emit();
  }

  onViewPhotos(): void {
    this.modalService.open({
      title: this.title,
      content: PhotoViewerComponent,
      width: 768,
      footer: false,
      componentParams: {
        id: this.componentParams.id
      }
    });
  }

}
